package client

import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
import constants.JobConstants
import server.MapleUnionFactory
import java.util.*
import java.util.concurrent.locks.ReentrantReadWriteLock


/**
 * 免责声明：本模拟器源代码下载自ragezone.com，仅用于技术研究学习，无任何商业行为。
 */
class MapleUnion @JsonCreator
constructor() {
    private val allCharacterData = HashMap<Int, MapleUnionData>()
    private val currUnionData = HashMap<Int, MapleUnionData>()
    private val boardDatas = HashMap<Int, BoardData>()
    private val skills = HashMap<Int, Int>()
    @Transient private val lock = ReentrantReadWriteLock()
    private val indexs = IntArray(16)
    private var rank: Int = 0

    init {
        init()
    }

    private fun init() {
        lock.writeLock().lock()
        try {
            for (i in indexs.indices) {
                indexs[i] = 0
            }
            skills.clear()
            boardDatas.clear()
            for ((key, value) in MapleUnionFactory.getBoardInfos()) {
                boardDatas.put(key, BoardData(key, (value).xPos, (value).yPos, (value).groupIndex))
            }
        } finally {
            lock.writeLock().unlock()
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    fun update() {
        lock.writeLock().lock()
        try {
            init()
            for (entry in currUnionData.entries) {
                val unionData = entry.value
                val boardinfos = MapleUnionFactory.getBoardInfos()[unionData.boardindex]
                if (boardinfos != null) {
                    val xPos = boardinfos.xPos
                    val yPos = boardinfos.yPos
                    val rotate = unionData.rotate
                    val job = unionData.job
                    val level = unionData.level
                    val grade = MapleUnionFactory.getGrade(job, level)
                    if (grade <= 0) {
                        continue
                    }
                    val characterSize = MapleUnionFactory.getCharacterSizeData(JobConstants.getJobBranch(unionData.job), grade - 1) ?: continue
                    val skillid = MapleUnionFactory.getCardSkillIDs(job, level)?.second as Int
                    if (skills.containsKey(skillid)) {
                        if (skills[skillid]!! < grade) {
                            skills.put(skillid, grade)
                        }
                    } else {
                        skills.put(skillid, grade)
                    }
                    for (entry2 in characterSize.entries) {
                        val n = rotate % 1000
                        val n2 = rotate / 1000
                        var x = entry2.value.x
                        var y = entry2.value.y
                        when (n2) {
                            1 -> {
                                x *= -1
                            }
                            2 -> {
                                y *= -1
                            }
                            3 -> {
                                x *= -1
                                y *= -1
                            }
                        }
                        val i = contians(xPos + Math.round(x * Math.cos(Math.toRadians(n.toDouble())) - y * Math.sin(Math.toRadians(n.toDouble()))).toInt(), yPos + Math.round(x * Math.sin(Math.toRadians(n.toDouble())) + y * Math.cos(Math.toRadians(n.toDouble()))).toInt())
                        i?.exist = true
                    }
                }
            }
            boardDatas.values
                    .filter { it.exist }
                    .forEach { ++indexs[it.groupIndex] }
        } finally {
            lock.writeLock().unlock()
        }
    }

    fun getTotalLevel(): Int {
        return allCharacterData.values.sumBy { it.level }
    }

    fun getRank(): Int {
        return rank
    }

    fun setRank(n2: Int) {
        rank = n2
    }

    private fun contians(xPos: Int, yPos: Int): BoardData? {
        return boardDatas.values.firstOrNull { it.xPos == xPos && it.yPos == yPos }
    }

    fun getSkills(): Map<Int, Int> {
        lock.readLock().lock()
        try {
            return skills
        } finally {
            lock.readLock().unlock()
        }
    }

    fun getCurrOnionMap(): Map<Int, MapleUnionData> {
        lock.readLock().lock()
        try {
            return currUnionData
        } finally {
            lock.readLock().unlock()
        }
    }

    fun getAllCharacterMap(): Map<Int, MapleUnionData> {
        lock.readLock().lock()
        try {
            return allCharacterData
        } finally {
            lock.readLock().unlock()
        }
    }

    fun getIndexs(): IntArray {
        return indexs
    }
}

data class BoardData @JsonCreator
constructor(
        @param:JsonProperty("boardInfoId") val boardInfoId: Int,
        @param:JsonProperty("xPos") val xPos: Int,
        @param:JsonProperty("yPos") val yPos: Int,
        @param:JsonProperty("groupIndex") val groupIndex: Int) {
    var exist: Boolean = false
}

data class MapleUnionData @JsonCreator
constructor(
        @param:JsonProperty("cid") val cid: Int,
        @param:JsonProperty("name") val name: String,
        @param:JsonProperty("level") val level: Int,
        @param:JsonProperty("job") val job: Int
) {
    var type = 1
    var rotate: Int = 0
    var boardindex = -1
    var local: Int = 0
}